﻿using PlantsZombies.View.ViewEx;
using System;
using System.Collections.Generic;
using System.Drawing.Drawing2D;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace PlantsZombies.View
{
    public class WaitingControl : Control
    {
        private int _numberofspokes = 20; //控件包含的总的辐条数量 
        private int _hotspokes = 5; //活动辐条数 
        private float _innerRadius; //内环半径,外环半径根据控件的大小计算 
        private Color _spokeColor = Color.LightGray;//辐条颜色
        private Color _hotSpokeColor = Color.Gray; //活动辐条颜色
        private int _thickness = 3; //辐条的宽度 
        private bool _antialias = true; //控件绘制时是否反走样 
        private bool _colockWise = true; //活动辐条是否顺时针旋转
        private List<PointF[]> _spokes; //辐条轮廓线列表 
        protected Color[] _palette; //渐变色调色板 
        private System.Windows.Forms.Timer _timer; //计时器 
        private Pen _pen; //绘制WaitingCircle的画笔 
        private int _offset = 0; //活动辐条偏移量
        public WaitingControl()
        {
            SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true);
            _timer = new System.Windows.Forms.Timer();
            _timer.Tick += _timer_Tick; ;
            _pen = new Pen(_spokeColor, _thickness);
            this.Text = "请稍等";
            this.Size = new Size(120, 120);
            GeneratePalette();
        }

        private void _timer_Tick(object sender, EventArgs e)
        {
            Invalidate();
            _offset = ((_colockWise ? --_offset : ++_offset) + _numberofspokes) % _numberofspokes;
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            CircleF c = new CircleF(ClientRectangle); c.Inflate(-5.0f);
            _innerRadius = c.Radius / 2.0f;
            _spokes = ExtendedShapes.CreateWaitCircleSpokes(c.Pivot, c.Radius, _innerRadius, _numberofspokes);
        }
        public float InnerRadius
        {
            get { return _innerRadius; }
            set
            {
                if (_innerRadius != value && value > 0)
                    _innerRadius = value;
                CircleF c = new CircleF(ClientRectangle);
                c.Inflate(-5.0f);
                _spokes = ExtendedShapes.CreateWaitCircleSpokes(c.Pivot, c.Radius, _innerRadius, _numberofspokes);
                Invalidate();
            }
        }

        public int NumberOfSpokes
        {
            get { return _numberofspokes; }
            set
            {
                _numberofspokes = Math.Max(2, Math.Max(_hotspokes, value)); CircleF c = new CircleF(ClientRectangle);
                c.Inflate(-5.0f);
                _spokes = ExtendedShapes.CreateWaitCircleSpokes(c.Pivot, c.Radius, _innerRadius, _numberofspokes);
                Invalidate();
            }
        }
        public LineCap StartCap
        {
            get { return _pen.StartCap; }
            set
            {
                _pen.StartCap = value; Invalidate();
            }
        }

        public LineCap EndCap
        {
            get { return _pen.EndCap; }
            set { _pen.EndCap = value; Invalidate(); }
        }
        public int Thickness
        {
            get { return _thickness; }
            set
            {
                if (value > 0)
                    _thickness = value; _pen.Width = _thickness; Invalidate();
            }
        }
        protected virtual void GeneratePalette()
        {
            _palette = new Color[_hotspokes];
            float a = (float)(_hotSpokeColor.A - _spokeColor.A) / (float)_hotspokes;
            float r = (float)(_hotSpokeColor.R - _spokeColor.R) / (float)_hotspokes;
            float g = (float)(_hotSpokeColor.G - _spokeColor.G) / (float)_hotspokes;
            float b = (float)(_hotSpokeColor.B - _spokeColor.B) / (float)_hotspokes;
            for (int i = 0; i < _hotspokes; i++)
            {
                _palette[i] = Color.FromArgb(_hotSpokeColor.A - (int)(i * a),
                _hotSpokeColor.R - (int)(i * r), _hotSpokeColor.G - (int)(i * g), _hotSpokeColor.B - (int)(i * b));
            }
        }
        public int Speed
        {
            get { return _timer.Interval; }
            set { _timer.Interval = value; }
        }
        public bool Activate
        {
            get { return _timer.Enabled; }
            set { _timer.Enabled = value; this.Invalidate(); }
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            DrawSpokes(e.Graphics);
        }
        protected void DrawSpokes(Graphics g)
        {
            g.SmoothingMode = _antialias ? SmoothingMode.AntiAlias : SmoothingMode.Default;
            if (!Activate)
            {
                _pen.Color = _spokeColor;
                foreach (PointF[] spoke in _spokes)
                {
                    g.DrawLines(_pen, spoke);
                }
            }
            else
            {
                List<int> hot = new List<int>(); //存储活动辐条的索引 
                for (int i = 0; i < _hotspokes; i++) //计算活动辐条的索引 
                {
                    int index = ((_colockWise ? _offset - i : _offset + i) + _numberofspokes) % _numberofspokes;
                    hot.Add(index);
                }
                _pen.Color = _spokeColor;
                for (int i = 0; i < _numberofspokes; i++)//首先绘制非活动辐条
                {
                    if (!hot.Contains(i))
                    {

                        g.DrawLines(_pen, _spokes[i]);
                    }
                }
                for (int i = 0; i < _hotspokes; i++) //绘制活动辐条 
                {
                    _pen.Color = _palette[_hotspokes - 1 - i];
                    g.DrawLines(_pen, _spokes[hot[i]]);
                }
            }
            if (!string.IsNullOrWhiteSpace(this.Text))
            {
                SizeF sf = this.Text.MeasureString(this.Font);
                SolidBrush solid = new SolidBrush(this.ForeColor);
                g.DrawString(this.Text, this.Font, solid, new PointF((this.Width - sf.Width) / 2, (this.Height - sf.Height) / 2));
                solid.Dispose();
            }
        }

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
            if (disposing)
            {
                _pen.Dispose();
                _timer?.Dispose();
            }
        }
    }
}
